##############################################################################################
#
# The magic.makefile Copyright 2004-2006 by Jeff Koftinoff <jeffk@jdkoftinoff.com>
# version 3.
#
# Simplifies the building of a c/c++ library, it's tests, tools, examples, and documentation.
#
# See https://clicker.jdkoftinoff.com/projects/trac/jdks/wiki/MagicMakefileV3
# for more information, including license information (GPL)
#


# default project settings. These are usually originally set in project.mak

# PROJECT is the single word describing this project.
PROJECT?=project

# PROJECT_NAME is a single line describing this project
PROJECT_NAME?=Project

# PROJECT_VERSION defaults to the date, YYYYMMDD
PROJECT_VERSION?=$(shell date +%Y%m%d)

# BINARY_TARBALL_NAME is the file name of the result tar ball when an installation directory is tarred and bzipped.
BINARY_TARBALL_NAME?=$(PROJECT_NAME)-$(PROJECT_VERSION).tar.bz2

# We put our build dir in $(PWD) by default
BUILD_DIR?=$(PWD)

NATIVE_BUILD_DIR=$(PWD)

# We are not cross compiling by default
CROSS_COMPILING?=0

# TOP_LIB_DIRS is a list of relative directories from the PROJECT_TOP_DIR that each contain
# an "include", "src", "tools", "tests" and other directories. Typically for a single project
# TOP_LIB_DIRS is set to '.' in project.mak

# LIB_DIRS is then calculated with the fully qualified directory name for each directory in TOP_LIB_DIRS
LIB_DIRS+=$(call add_top_dir_prefix,$(TOP_LIB_DIRS))


# RSYNC is the name of our rsync program.
RSYNC?=rsync

# RSYNC_OPTIONS are the rsync options we use to copy a tree of files/directories to another dir.
# We want ot exclude backup files and subversion and CVS control directories.
RSYNC_OPTIONS?=-a --exclude='*~' --exclude='.svn' --exclude='CVS'

# When we build a config tool script, this is the file name we use. 
PROJECT_CONFIG_TOOL?=$(PROJECT)-cfg

OBJDUMP?=$(COMPILER_PREFIX)objdump
OBJDUMP_FLAGS?=-d -S


##############################################################################################
#
# utility functions 

# add_top_dir_prefix is a function that takes every directory and or wildcard pattern 
# in arg1 and prefixes PROJECT_TOP_DIR to it, and then only expands the directories that actually exist.

add_top_dir_prefix=$(strip $(wildcard $(foreach lib,$(1),$(PROJECT_TOP_DIR)/$(lib))))


# subdirs_in_path is a function which takes 1 parameter:
#  $(1) is a single directory
# it expands to a list of all directories in $(1)

subdirs_in_path=$(strip $(foreach d,$(wildcard $(1)/*/.),$(dir $(d))))

bare_subdirs_in_path=$(subst /,,$(subst $(1),,$(call subdirs_in_path,$(1))))

# suffix_platform_dirs is a function that takes 3 parameters:
#  $(1) is a subdirectory name, like 'src'
#  $(2) is a list of platform directories, like 'win32' or 'posix'
#  $(3) is a list of main directory names, like '$(PROJECT_TOP_DIR)'
# 
# suffix_platform_dirs expands all existing directories that match any of $(3)/$(1) or $(3)/$(1)/$(2)


suffix_platform_dirs=$(strip $(foreach dir,$(addsuffix /$(1),$(3)) $(foreach platform,$(2),$(addsuffix /$(1)/$(platform),$(3))),$(wildcard $(dir))))


# targe_suffix_platform_dirs is a function which takes one parameter:
#  $(1) is a subdirectory name, like 'src' or 'tool'
# it expands into all existing directories for the target platform sources

target_suffix_platform_dirs=$(wildcard $(call suffix_platform_dirs,$(1),$(PLATFORM_DIRS),$(LIB_DIRS)))

# native_suffix_platform_dirs is a function which takes one parameter:
#  $(1) is a subdirectory name, like 'src' or 'tool'
# it expands into all existing directories for the native platform sources

native_suffix_platform_dirs=$(wildcard $(call suffix_platform_dirs,$(1),$(NATIVE_PLATFORM_DIRS),$(LIB_DIRS)))

# get_file_list is a function which takes two parameters:
#  $(1) a list of directory names
#  $(2) a file extension (without the dot)
# it expands into all the file names that are found in the listed directories which that file extension,
# and then removes all the directory names from the results.

get_file_list=$(strip $(notdir $(foreach dir,$(1),$(wildcard $(dir)/*.$(2)))))


# get_src_file_list is a function which takes one parameter:
#  $(1) is a file extension
# it expands into a list of all source files for the target platform that of that type
# (with the directory names removed)

get_src_file_list=$(call get_file_list,$(LIB_SRC_DIR),$(1))
get_native_src_file_list=$(call get_file_list,$(NATIVE_LIB_SRC_DIR),$(1))


# get_cpp_o_files is a function which takes one parameter:
#  $(1) is a list of cpp files with no directory names
#
# it returns the full path names for all the required object files which are generated by cpp files.
# get_cc_o_files, get_c_o_files, get_m_o_files, and get_mm_o_files are the same as get_cpp_o_files 
# except for C, Objective-C, and Objective-C++ respectively.

get_cpp_o_files=$(addprefix $(OUTPUT_OBJ_DIR)/,$(1:.cpp=.o))
get_cc_o_files=$(addprefix $(OUTPUT_OBJ_DIR)/,$(1:.cc=.o))
get_c_o_files=$(addprefix $(OUTPUT_OBJ_DIR)/,$(1:.c=.o))
get_m_o_files=$(addprefix $(OUTPUT_OBJ_DIR)/,$(1:.m=.o))
get_mm_o_files=$(addprefix $(OUTPUT_OBJ_DIR)/,$(1:.mm=.o))
get_rc_o_files=$(addprefix $(OUTPUT_OBJ_DIR)/,$(1:.rc=.o))

get_native_cpp_o_files=$(addprefix $(NATIVE_OUTPUT_OBJ_DIR)/,$(1:.cpp=.o))
get_native_cc_o_files=$(addprefix $(NATIVE_OUTPUT_OBJ_DIR)/,$(1:.cc=.o))
get_native_c_o_files=$(addprefix $(NATIVE_OUTPUT_OBJ_DIR)/,$(1:.c=.o))
get_native_m_o_files=$(addprefix $(NATIVE_OUTPUT_OBJ_DIR)/,$(1:.m=.o))
get_native_mm_o_files=$(addprefix $(NATIVE_OUTPUT_OBJ_DIR)/,$(1:.mm=.o))
get_native_rc_o_files=$(addprefix $(NATIVE_OUTPUT_OBJ_DIR)/,$(1:.rc=.o))



# calc_target_options is a function which takes 1 parameter:
#   $(1) is a target platform suffix, such as MINGW32, POSIX, or LINUX
# 
# it expands into makefile code which is to be ultimately eval'd - 
# this means that if $(1) is LINUX, then for instance, COMPILE_FLAGS_LINUX
# will get appended to the current COMPILE_FLAGS.
# the variables set in this fashion include:
#  LIB_SRC_DIR, DEFINES, COMPILE_FLAGS, LINK_FLAGS, LINK_FLAGS_GUI, LDLIBS, and LDLIBS_GUI

define calc_target_options
# add the relevant top src dirs
LIB_SRC_DIR+=$$(call add_top_dir_prefix,$$(TOP_LIB_DIRS_$(1)))

# set the target platform macro definition
DEFINES+=TARGET_PLATFORM_$(1)=1

# set the platform specific project defines
DEFINES+=$$(DEFINES_$(1))

# set the platform specific project compile flags
COMPILE_FLAGS+=$$(COMPILE_FLAGS_$(1))

# set the platform specific project pre-process flags
PREPROCESS_FLAGS+=$$(PREPROCESS_FLAGS_$(1))

# set the platform specific project link flags
LINK_FLAGS+=$$(LINK_FLAGS_$(1))

# set the platform specific project gui link flags
LINK_FLAGS_GUI+=$$(LINK_FLAGS_GUI_$(1))

# set the platform specific project link libs
LDLIBS+=$$(LDLIBS_$(1))

# set the platform specific project gui link libs
LDLIBS_GUI+=$$(LDLIBS_GUI_$(1))
endef


# calc_multi_target_options is a function which takes 1 parameter:
#  $(1) is a list of target platform suffixes, such as POSIX or LINUX
# it takes each one and expands them via the calc_target_options function.
# this expansion is to be eval'd.

calc_multi_target_options=$(foreach suffix,$(1),$(call calc_target_options,$(suffix)))


# calc_native_options is a function which takes 1 parameter:
#   $(1) is a native platform suffix, such as MINGW32, POSIX, or LINUX
# 
# it expands into makefile code which is to be ultimately eval'd - 
# this means that if $(1) is LINUX, then for instance, COMPILE_FLAGS_LINUX
# will get appended to the current NATIVE_COMPILE_FLAGS.
# the variables set in this fashion include:
#  NATIVE_LIB_SRC_DIR, NATIVE_DEFINES, NATIVE_COMPILE_FLAGS, 
#  NATIVE_LINK_FLAGS, NATIVE_LINK_FLAGS_GUI, NATIVE_LDLIBS, and NATIVE_LDLIBS_GUI

define calc_native_options
# add the relevant top src dirs
NATIVE_LIB_SRC_DIR+=$$(call add_top_dir_prefix,$$(TOP_LIB_DIRS_$(1)))

# set the target platform macro definition
NATIVE_DEFINES+=TARGET_PLATFORM_$(1)=1

# set the platform specific project defines
NATIVE_DEFINES+=$$(DEFINES_$(1))

# set the platform specific project compile flags
NATIVE_COMPILE_FLAGS+=$$(COMPILE_FLAGS_$(1))

# set the platform specific project preprocess flags
NATIVE_PREPROCESS_FLAGS+=$$(PREPROCESS_FLAGS_$(1))

# set the platform specific project link flags
NATIVE_LINK_FLAGS+=$$(LINK_FLAGS_$(1))

# set the platform specific project gui link flags
NATIVE_LINK_FLAGS_GUI+=$$(LINK_FLAGS_GUI_$(1))

# set the platform specific project link libs
NATIVE_LDLIBS+=$$(LDLIBS_$(1))

# set the platform specific project gui link libs
NATIVE_LDLIBS_GUI+=$$(LDLIBS_GUI_$(1))
endef


# calc_multi_native_options is a function which takes 1 parameter:
#  $(1) is a list of native platform suffixes, such as POSIX or LINUX
# it takes each one and expands them via the calc_native_options function.
# this expansion is to be eval'd.

calc_multi_native_options=$(foreach suffix,$(1),$(call calc_native_options,$(suffix)))


# search_program_group is a function which returns the makefile text required to find
# all source files in a specified directory class and construct the o file lists for them.
# Param $(1) is the class of program in capitals, for example TOOLS, TESTS, EXAMPLES, GUI
# the text returned by this function is then to be eval'd.  The appropriate lists of 
# source files and O files for this class are then created dynamically.

define search_program_group
LIB_$(1)_CPP_FILES=$$(call get_file_list,$$(LIB_$(1)_DIR),cpp)
LIB_$(1)_CC_FILES=$$(call get_file_list,$$(LIB_$(1)_DIR),cc)
LIB_$(1)_C_FILES=$$(call get_file_list,$$(LIB_$(1)_DIR),c)
LIB_$(1)_M_FILES=$$(call get_file_list,$$(LIB_$(1)_DIR),m)
LIB_$(1)_MM_FILES=$$(call get_file_list,$$(LIB_$(1)_DIR),mm)
LIB_$(1)_RC_FILES=$$(call get_file_list,$$(LIB_$(1)_DIR),rc)
LIB_$(1)_SH_FILES=$$(call get_file_list,$$(LIB_$(1)_DIR),sh)

LIB_$(1)_O_FILES=$$(call get_cpp_o_files,$$(LIB_$(1)_CPP_FILES)) \
	$$(call get_cc_o_files,$$(LIB_$(1)_CC_FILES)) \
	$$(call get_c_o_files,$$(LIB_$(1)_C_FILES)) \
	$$(call get_m_o_files,$$(LIB_$(1)_M_FILES)) \
	$$(call get_mm_o_files,$$(LIB_$(1)_MM_FILES)) \
	$$(call get_rc_o_files,$$(LIB_$(1)_RC_FILES))

LIB_$(1)_DISASM_FILES=$$(LIB_$(1)_O_FILES:.o=.disasm)

LIB_$(1)_EXE_FILES=$$(addprefix $$(OUTPUT_$(1)_DIR)/,$$(notdir $$(LIB_$(1)_O_FILES:.o=$$(EXE))))

ifeq ($(CROSS_COMPILING),1)
NATIVE_LIB_$(1)_CPP_FILES=$$(call get_file_list,$$(NATIVE_LIB_$(1)_DIR),cpp)
NATIVE_LIB_$(1)_CC_FILES=$$(call get_file_list,$$(NATIVE_LIB_$(1)_DIR),cc)
NATIVE_LIB_$(1)_C_FILES=$$(call get_file_list,$$(NATIVE_LIB_$(1)_DIR),c)
NATIVE_LIB_$(1)_M_FILES=$$(call get_file_list,$$(NATIVE_LIB_$(1)_DIR),m)
NATIVE_LIB_$(1)_MM_FILES=$$(call get_file_list,$$(NATIVE_LIB_$(1)_DIR),mm)
NATIVE_LIB_$(1)_SH_FILES=$$(call get_file_list,$$(NATIVE_LIB_$(1)_DIR),sh)
NATIVE_LIB_$(1)_RC_FILES=$$(call get_file_list,$$(NATIVE_LIB_$(1)_DIR),rc)

NATIVE_LIB_TOOLS_O_FILES=$$(call get_native_cpp_o_files,$$(NATIVE_LIB_$(1)_CPP_FILES)) \
	$$(call get_native_cc_o_files,$$(NATIVE_LIB_$(1)_CC_FILES)) \
	$$(call get_native_c_o_files,$$(NATIVE_LIB_$(1)_C_FILES)) \
	$$(call get_native_m_o_files,$$(NATIVE_LIB_$(1)_M_FILES)) \
	$$(call get_native_mm_o_files,$$(NATIVE_LIB_$(1)_MM_FILES)) \
	$$(call get_native_rc_o_files,$$(NATIVE_LIB_$(1)_RC_FILES))

NATIVE_LIB_$(1)_EXE_FILES=$$(addprefix $$(NATIVE_OUTPUT_$(1)_DIR)/,$$(notdir $$(NATIVE_LIB_$(1)_O_FILES:.o=$$(NATIVE_EXE))))
endif
endef

# compile options

# having DEBUG set to 1 means we compile with -g and define DEBUG=1

ifeq ($(DEBUG),1)
COMPILE_FLAGS+=-g
DEFINES+=DEBUG=1
endif

# having PROFILE set to 1 means we compile with -pg 

ifeq ($(PROFILE),1)
COMPILE_FLAGS+=-pg
endif

# all our */include directories
INCLUDES+=$(LIB_INCLUDE_DIR)

# our compiler defines
DEFINES?=

# The preprocessor flags is initially comprised of -I option for each include dir, 
# and the -D option for each define
PREPROCESS_FLAGS+=$(addprefix -I,$(INCLUDES)) $(addprefix -D,$(DEFINES)) 

# The compiler flag settings for optimization and warnings
COMPILE_FLAGS+=$(OPTIMIZE) $(WARNINGS)

# the additional linker flags:
LDFLAGS+=

# the addition linker libraries:
LDLIBS+=

# The preprocessor flags needed to generate dependency information:
DEPENDENCY_OPTIONS?=-MM 

# native platform debug flags: having NATIVE_DEBUG set to 1 means we compile native platform
# code with -g and define DEBUG=1
ifeq ($(NATIVE_DEBUG),1)
NATIVE_COMPILE_FLAGS+=-g
NATIVE_DEFINES+=DEBUG=1
endif

# native platform profile flag: having NATIVE_PROFILE set to 1 means we compile native platform
# code with -pg 
ifeq ($(NATIVE_PROFILE),1)
NATIVE_COMPILE_FLAGS+=-pg
endif


# The native platform preprocessor flags is initially comprised of -I option for each include dir, 
# and the -D option for each define
NATIVE_PREPROCESS_FLAGS=$(addprefix -I,$(INCLUDES)) $(addprefix -D,$(NATIVE_DEFINES)) 

# The native platform compiler flags settings for optimization and warnings
NATIVE_COMPILE_FLAGS+=$(NATIVE_OPTIMIZE) $(NATIVE_WARNINGS)

# the additional linker flags:
NATIVE_LDFLAGS+=

# the addition linker libraries:
NATIVE_LDLIBS+=



# config tool generation options

# CONFIG_TOOL_FILE is the full path name of the generated config tool script
CONFIG_TOOL_FILE=$(OUTPUT_TOOLS_DIR)/$(PROJECT_CONFIG_TOOL)

# CONFIG_TOOL_PREPROCESS_FLAGS is the preprocessor flags that the config tool script 
# will output when given --cppflags
CONFIG_TOOL_PREPROCESS_FLAGS+=$(addprefix -I,$(INSTALL_INCLUDE_DIR)) $(addprefix -D,$(DEFINES))

# CONFIG_TOOL_COMPILE_FLAGS is the full compile flags that the config tool script 
# will output when given --cflags or --cxxflags
CONFIG_TOOL_COMPILE_FLAGS+=$(WARNINGS) $(OPTIMIZE) $(CONFIG_TOOL_PREPROCESS_FLAGS) $(COMPILE_FLAGS)



# mingw32 is a subset of win32
ifeq ($(TARGET_PLATFORM_MINGW32),1)
SUFFIXES_TARGET_PLATFORM=MINGW32 WIN32
EXE=.exe
PLATFORM_DIRS+=win32 mingw32
endif


# cygwin is really a subset of posix
ifeq ($(TARGET_PLATFORM_CYGWIN),1)
SUFFIXES_TARGET_PLATFORM=CYGWIN POSIX
EXE=.exe
PLATFORM_DIRS+=cygwin posix
endif

# plain posix is just posix
ifeq ($(TARGET_PLATFORM_POSIX),1)
SUFFIXES_TARGET_PLATFORM=POSIX
PLATFORM_DIRS+=posix
endif

# linux is a subset of posix
ifeq ($(TARGET_PLATFORM_LINUX),1)
SUFFIXES_TARGET_PLATFORM=POSIX LINUX
PLATFORM_DIRS+=posix linux
endif


# linux-i386 is a subset of linux, posix
ifeq ($(TARGET_PLATFORM_LINUX_I386),1)
SUFFIXES_TARGET_PLATFORM=POSIX LINUX LINUX_I386
PLATFORM_DIRS+=posix linux
endif

# linux-ppc is a subset of linux, posix
ifeq ($(TARGET_PLATFORM_LINUX_PPC),1)
SUFFIXES_TARGET_PLATFORM=POSIX LINUX LINUX_PPC
PLATFORM_DIRS+=posix linux
endif

# macosx is a subset of posix
ifeq ($(TARGET_PLATFORM_MACOSX),1)
SUFFIXES_TARGET_PLATFORM=POSIX MACOSX
PLATFORM_DIRS+=posix macosx
endif

# macosx_ppc is a subset of macosx and posix
ifeq ($(TARGET_PLATFORM_MACOSX_PPC),1)
SUFFIXES_TARGET_PLATFORM=POSIX MACOSX MACOSX_PPC
PLATFORM_DIRS+=posix macosx macosx-ppc
endif

# macosx_i386 is a subset of macosx and posix
ifeq ($(TARGET_PLATFORM_MACOSX_I386),1)
SUFFIXES_TARGET_PLATFORM=POSIX MACOSX MACOSX_I386
PLATFORM_DIRS+=posix macosx macosx-i386
endif

# macosx_universal is a subset of macosx and posix and uses mac libtool to generate fat binaries.
ifeq ($(TARGET_PLATFORM_MACOSX_UNIVERSAL),1)
SUFFIXES_TARGET_PLATFORM=POSIX MACOSX MACOSX_UNIVERSAL
PLATFORM_DIRS+=posix macosx macosx-ppc macosx-i386
TARGET_MACOSX_SDK?=/Developer/SDKs/MacOSX10.4u.sdk
COMPILE_FLAGS+=-isysroot $(TARGET_MACOSX_SDK) -arch i386 -arch ppc
LINK_FLAGS+=-isysroot $(TARGET_MACOSX_SDK) -arch i386 -arch ppc
TARGET_USE_AR=0
TARGET_USE_MACOSX_LIBTOOL=1
MACOSX_LIBTOOL=libtool
MACOSX_LIBTOOLFLAGS?=-static
endif

# if EXE suffix is not set then it ought to be blank.
EXE?=

# If we are to use normal gnu 'ar' to manipulate static libraries for the target platform,
# TARGET_USE_AR is to be set to 1. Defaults to 1.
TARGET_USE_AR?=1

# If we are to use mac os x libtool (tiger and beyond) to manipulate static libraries for the target
# platform, TARGET_USE_MACOSX_LIBTOOL is to be set to 1 instead. Defaults to 0.
TARGET_USE_MACOSX_LIBTOOL?=0


# Now we know all our target platform suffixes in SUFFIXES_TARGET_PLATFORM, so
# we eval the result of the calc_multi_target_options function. This effectively merges in
# the platform specific defines, compile flags, and link flags

$(eval $(call calc_multi_target_options,$(SUFFIXES_TARGET_PLATFORM)))


##############################################################################################
#
# Calculate all our source dirs for various things, for our target platform
#
LIB_INCLUDE_DIR+=$(call target_suffix_platform_dirs,include)
LIB_SRC_DIR+=$(call target_suffix_platform_dirs,src)
LIB_TESTS_DIR+=$(call target_suffix_platform_dirs,tests)
LIB_GUI_DIR+=$(call target_suffix_platform_dirs,gui)
LIB_EXAMPLES_DIR+=$(call target_suffix_platform_dirs,examples)
LIB_TOOLS_DIR+=$(call target_suffix_platform_dirs,tools)
LIB_DOCS_DIR+=$(call target_suffix_platform_dirs,docs)

ALL_SOURCES_DIRS=$(strip $(LIB_SRC_DIR) $(LIB_TESTS_DIR) $(LIB_GUI_DIR) $(LIB_EXAMPLES_DIR) $(LIB_TOOLS_DIR))

# calculate our output directories for our target platform results
OUTPUT_DIR=$(BUILD_DIR)/build
OUTPUT_LIB_DIR?=$(OUTPUT_DIR)/lib
OUTPUT_TESTS_DIR?=$(OUTPUT_DIR)/tests
OUTPUT_DOCS_DIR?=$(OUTPUT_DIR)/docs
OUTPUT_TOOLS_DIR?=$(OUTPUT_DIR)/tools
OUTPUT_GUI_DIR?=$(OUTPUT_DIR)/gui
OUTPUT_EXAMPLES_DIR?=$(OUTPUT_DIR)/examples
OUTPUT_OBJ_DIR?=$(OUTPUT_DIR)/obj

# our output libraries name is simply our project name prefixed with lib in our output lib dir.

INSTALL_DIR?=$(BUILD_DIR)/$(PROJECT)-$(PROJECT_VERSION)
INSTALL_BIN_DIR?=$(INSTALL_DIR)/bin
INSTALL_LIB_DIR?=$(INSTALL_DIR)/lib
INSTALL_INCLUDE_DIR?=$(INSTALL_DIR)/include
INSTALL_DOCS_DIR?=$(INSTALL_DIR)/docs
INSTALL_DOCS_DIR?=$(INSTALL_DIR)/share/$(PROJECT)-$(PROJECT_VERSION)

ALL_OUTPUT_DIRS+=$(OUTPUT_LIB_DIR) $(OUTPUT_TOOLS_DIR) $(OUTPUT_TESTS_DIR) $(OUTPUT_DOCS_DIR) $(OUTPUT_EXAMPLES_DIR) $(OUTPUT_OBJ_DIR) $(OUTPUT_GUI_DIR)



NATIVE_USE_AR?=1
NATIVE_USE_MACOSX_LIBTOOL?=0


ifeq ($(NATIVE_PLATFORM_MINGW32),1)
SUFFIXES_NATIVE_PLATFORM=MINGW32 WIN32
NATIVE_PLATFORM_GENERIC=0
NATIVE_EXE=.exe
NATIVE_PLATFORM_DIRS+=win32 mingw32
endif

ifeq ($(NATIVE_PLATFORM_CYGWIN),1)
SUFFIXES_NATIVE_PLATFORM=CYGWIN POSIX
NATIVE_PLATFORM_GENERIC=0
NATIVE_EXE=.exe
NATIVE_PLATFORM_DIRS+=cygwin posix
endif

ifeq ($(NATIVE_PLATFORM_POSIX),1)
SUFFIXES_NATIVE_PLATFORM=POSIX
NATIVE_PLATFORM_GENERIC=0
NATIVE_EXE=
NATIVE_PLATFORM_DIRS+=posix
endif

ifeq ($(NATIVE_PLATFORM_LINUX),1)
SUFFIXES_NATIVE_PLATFORM=POSIX LINUX
NATIVE_PLATFORM_GENERIC=0
NATIVE_EXE=
NATIVE_PLATFORM_DIRS+=posix linux
endif

ifeq ($(NATIVE_PLATFORM_LINUX_I386),1)
SUFFIXES_NATIVE_PLATFORM=POSIX LINUX LINUX_I386
NATIVE_PLATFORM_GENERIC=0
NATIVE_EXE=
NATIVE_PLATFORM_DIRS+=posix linux
endif

ifeq ($(NATIVE_PLATFORM_LINUX_PPC),1)
SUFFIXES_NATIVE_PLATFORM=POSIX LINUX LINUX_PPC
NATIVE_PLATFORM_GENERIC=0
NATIVE_EXE=
NATIVE_PLATFORM_DIRS+=posix linux
endif

ifeq ($(NATIVE_PLATFORM_MACOSX),1)
SUFFIXES_NATIVE_PLATFORM=POSIX MACOSX
NATIVE_PLATFORM_GENERIC=0
NATIVE_EXE=
NATIVE_PLATFORM_DIRS+=posix macosx
endif

ifeq ($(NATIVE_PLATFORM_MACOSX_PPC),1)
SUFFIXES_NATIVE_PLATFORM=POSIX MACOSX MACOSX_PPC
NATIVE_PLATFORM_GENERIC=0
NATIVE_EXE=
NATIVE_PLATFORM_DIRS+=posix macosx macosx-ppc
endif

ifeq ($(NATIVE_PLATFORM_MACOSX_I386),1)
SUFFIXES_NATIVE_PLATFORM=POSIX MACOSX MACOSX_I386
NATIVE_PLATFORM_GENERIC=0
NATIVE_EXE=
NATIVE_PLATFORM_DIRS+=posix macosx macosx-i386
endif

ifeq ($(NATIVE_PLATFORM_MACOSX_UNIVERSAL),1)
SUFFIXES_NATIVE_PLATFORM=POSIX MACOSX MACOSX_UNIVERSAL
NATIVE_PLATFORM_GENERIC=0
NATIVE_EXE=
NATIVE_PLATFORM_DIRS+=posix macosx macosx-ppc macosx-i386
NATIVE_MACOSX_SDK?=/Developer/SDKs/MacOSX10.4u.sdk
NATIVE_COMPILE_FLAGS+=-isysroot $(TARGET_MACOSX_SDK) -arch i386 -arch ppc
NATIVE_LINK_FLAGS+=-isysroot $(TARGET_MACOSX_SDK) -arch i386 -arch ppc
NATIVE_USE_AR=0
NATIVE_USE_MACOSX_LIBTOOL=1
NATIVE_MACOSX_LIBTOOL=libtool
NATIVE_MACOSX_LIBTOOLFLAGS?=-static
endif


$(eval $(call calc_multi_native_options,$(SUFFIXES_NATIVE_PLATFORM)))


# calculate our output directories for our native platform results

NATIVE_OUTPUT_DIR=$(NATIVE_BUILD_DIR)/native
NATIVE_OUTPUT_LIB_DIR?=$(NATIVE_OUTPUT_DIR)/lib
NATIVE_OUTPUT_TESTS_DIR?=$(NATIVE_OUTPUT_DIR)/tests
NATIVE_OUTPUT_DOCS_DIR?=$(NATIVE_OUTPUT_DIR)/docs
NATIVE_OUTPUT_TOOLS_DIR?=$(NATIVE_OUTPUT_DIR)/tools
NATIVE_OUTPUT_EXAMPLES_DIR?=$(NATIVE_OUTPUT_DIR)/examples
NATIVE_OUTPUT_OBJ_DIR?=$(NATIVE_OUTPUT_DIR)/obj



NATIVE_LIB_SRC_DIR+=$(call native_suffix_platform_dirs,tests)
NATIVE_LIB_TESTS_DIR+=$(call native_suffix_platform_dirs,tests)
NATIVE_LIB_GUI_DIR+=$(call native_suffix_platform_dirs,gui)
NATIVE_LIB_EXAMPLES_DIR+=$(call native_suffix_platform_dirs,examples)
NATIVE_LIB_TOOLS_DIR+=$(call native_suffix_platform_dirs,tools)
NATIVE_ALL_SOURCES_DIRS=$(strip $(NATIVE_LIB_SRC_DIR) $(NATIVE_LIB_TESTS_DIR) $(NATIVE_LIB_GUI_DIR) $(NATIVE_LIB_EXAMPLES_DIR) $(NATIVE_LIB_TOOLS_DIR))

NATIVE_ALL_OUTPUT_DIRS+=$(NATIVE_OUTPUT_LIB_DIR) $(NATIVE_OUTPUT_TOOLS_DIR) $(NATIVE_OUTPUT_TESTS_DIR) $(NATIVE_OUTPUT_DOCS_DIR) $(NATIVE_OUTPUT_EXAMPLES_DIR) $(NATIVE_OUTPUT_OBJ_DIR) 



##############################################################################################
#
# our vpaths
#

# all o files in $(OUTPUT_OBJ_DIR)
vpath %.o $(OUTPUT_OBJ_DIR)

# all source files in all of our src,tests,ecxamples,tools,gui dirs
vpath %.m $(LIB_SRC_DIR) $(LIB_TESTS_DIR) $(LIB_EXAMPLES_DIR) $(LIB_TOOLS_DIR) $(LIB_GUI_DIR)
vpath %.mm $(LIB_SRC_DIR) $(LIB_TESTS_DIR) $(LIB_EXAMPLES_DIR) $(LIB_TOOLS_DIR) $(LIB_GUI_DIR)
vpath %.cpp $(LIB_SRC_DIR) $(LIB_TESTS_DIR) $(LIB_EXAMPLES_DIR) $(LIB_TOOLS_DIR) $(LIB_GUI_DIR)
vpath %.cc $(LIB_SRC_DIR) $(LIB_TESTS_DIR) $(LIB_EXAMPLES_DIR) $(LIB_TOOLS_DIR) $(LIB_GUI_DIR)
vpath %.c $(LIB_SRC_DIR) $(LIB_TESTS_DIR) $(LIB_EXAMPLES_DIR) $(LIB_TOOLS_DIR) $(LIB_GUI_DIR)
vpath %.rc $(LIB_SRC_DIR) $(LIB_TESTS_DIR) $(LIB_EXAMPLES_DIR) $(LIB_TOOLS_DIR) $(LIB_GUI_DIR)

# all h files in our include dirs
vpath %.h .:$(LIB_INCLUDE_DIR)

# all libraries in our OUTPUT_LIB_DIR
vpath %.a $(OUTPUT_LIB_DIR)
vpath %.so $(OUTPUT_LIB_DIR)

# all testing shell scripts in our tests source dir
vpath %.sh $(LIB_TESTS_DIR)

# all object files are precious. Make should not delete them even if they are intermediate
.PRECIOUS : $(OUTPUT_OBJ_DIR)/%.o

# If we are cross compiling, then we must also look in our native dirs for objects and libraries.
ifeq ($(CROSS_COMPILING),1)
vpath %.o $(NATIVE_OUTPUT_OBJ_DIR)
vpath %.a $(NATIVE_OUTPUT_LIB_DIR)
.PRECIOUS : $(NATIVE_OUTPUT_OBJ_DIR)/%.o
endif


##############################################################################################
#
# Make's rules.


# Remove make's built-in rules that we do not want

(%.o) : %.o

%.o : %.cpp

%.o : %.cc

%.o : %.rc

%.o : %.c

%.o : %.m

%.o : %.mm

%$(EXE) : %.cpp

%$(EXE) : %.cc

%$(EXE) : %.c

%$(EXE) : %.m

%$(EXE) : %.mm

COMPILE.cpp=$(CXX) $(CXXFLAGS) -c
COMPILE.cc=$(CXX) $(CXXFLAGS) -c
COMPILE.c=$(CC) $(CFLAGS) -c
COMPILE.mm=$(CXX) $(MMFLAGS) -c
COMPILE.m=$(CC) $(MFLAGS) -c
COMPILE.rc=$(WINDRES) 

LINK.cpp=$(CXX) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
LINK.cc=$(CXX) $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
LINK.c=$(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS)
LINK.mm=$(CXX) $(MMFLAGS) $(LDFLAGS) $(LDLIBS)
LINK.m=$(CC) $(MFLAGS) $(LDFLAGS) $(LDLIBS)

NATIVE_COMPILE.cpp=$(NATIVE_CXX) $(NATIVE_CXXFLAGS) -c
NATIVE_COMPILE.cc=$(NATIVE_CX) $(NATIVE_CXXFLAGS) -c
NATIVE_COMPILE.c=$(NATIVE_CC) $(NATIVE_CFLAGS) -c
NATIVE_COMPILE.mm=$(NATIVE_CXX) $(NATIVE_MMFLAGS) -c
NATIVE_COMPILE.m=$(NATIVE_CC) $(NATIVE_MFLAGS) -c
NATIVE_COMPILE.rc=$(NATIVE_WINDRES)

NATIVE_LINK.cpp=$(NATIVE_CXX) $(NATIVE_CXXFLAGS) $(NATIVE_LDFLAGS) $(NATIVE_LDLIBS)
NATIVE_LINK.cc=$(NATIVE_CXX) $(NATIVE_CXXFLAGS) $(NATIVE_LDFLAGS) $(NATIVE_LDLIBS)
NATIVE_LINK.c=$(NATIVE_CC) $(NATIVE_CFLAGS) $(NATIVE_LDFLAGS) $(NATIVE_LDLIBS)
NATIVE_LINK.mm=$(NATIVE_CXX) $(NATIVE_MMFLAGS) $(NATIVE_LDFLAGS) $(NATIVE_LDLIBS)
NATIVE_LINK.m=$(NATIVE_CC) $(NATIVE_MFLAGS) $(NATIVE_LDFLAGS) $(NATIVE_LDLIBS)


##############################################################################################
# 
# Replace make's original rules  with our special rules, which place output objects 
# directly in $(OUTPUT_OBJ_DIR), and also perform include file dependancy file creation.

# For Objective C++:
$(OUTPUT_OBJ_DIR)/%.o $(OUTPUT_OBJ_DIR)/%.d : %.mm
	@echo "CXX mm : $(notdir $<)"
	@$(CXX) $(PREPROCESS_FLAGS) $(MMFLAGS) $(DEPENDENCY_OPTIONS) -MT '$(OUTPUT_OBJ_DIR)'/$*.o -MF $(OUTPUT_OBJ_DIR)/$*.d $< &&	$(COMPILE.cpp) $(PREPROCESS_FLAGS) $(COMPILE_FLAGS) -o $(OUTPUT_OBJ_DIR)/$*.o $< 

# For Objective C:
$(OUTPUT_OBJ_DIR)/%.o $(OUTPUT_OBJ_DIR)/%.d : %.m
	@echo "CC  m  : $(notdir $<)"
	@$(CC) $(PREPROCESS_FLAGS) $(MFLAGS) $(DEPENDENCY_OPTIONS) -MT  '$(OUTPUT_OBJ_DIR)'/$*.o -MF $(OUTPUT_OBJ_DIR)/$*.d $< &&	$(COMPILE.c) $(PREPROCESS_FLAGS) $(COMPILE_FLAGS) -o $(OUTPUT_OBJ_DIR)/$*.o $<

# For C++: (cpp)
$(OUTPUT_OBJ_DIR)/%.o $(OUTPUT_OBJ_DIR)/%.d : %.cpp
	@echo "CXX    : $(notdir $<)"
	@$(CXX) $(PREPROCESS_FLAGS)  $(DEPENDENCY_OPTIONS) -MT '$(OUTPUT_OBJ_DIR)'/$*.o -MF $(OUTPUT_OBJ_DIR)/$*.d $< && $(COMPILE.cpp) $(PREPROCESS_FLAGS) $(COMPILE_FLAGS) -o $(OUTPUT_OBJ_DIR)/$*.o $<

# For C++: (cc)
$(OUTPUT_OBJ_DIR)/%.o $(OUTPUT_OBJ_DIR)/%.d : %.cc
	@echo "CXX    : $(notdir $<)"
	@$(CXX) $(PREPROCESS_FLAGS)  $(DEPENDENCY_OPTIONS) -MT  '$(OUTPUT_OBJ_DIR)'/$*.o -MF $(OUTPUT_OBJ_DIR)/$*.d $< && $(COMPILE.cc) $(PREPROCESS_FLAGS) $(COMPILE_FLAGS) -o $(OUTPUT_OBJ_DIR)/$*.o $<

# For C:
$(OUTPUT_OBJ_DIR)/%.o $(OUTPUT_OBJ_DIR)/%.d : %.c
	@echo "CC     : $(notdir $<)"
	@$(CC) $(PREPROCESS_FLAGS)  $(DEPENDENCY_OPTIONS) -MT  '$(OUTPUT_OBJ_DIR)'/$*.o -MF $(OUTPUT_OBJ_DIR)/$*.d $< && $(COMPILE.c) $(PREPROCESS_FLAGS) $(COMPILE_FLAGS) -o $(OUTPUT_OBJ_DIR)/$*.o $<

# For RC (windows):
$(OUTPUT_OBJ_DIR)/%.o : %.rc
	@echo "WINDRES     : $(notdir $<)"
	@$(COMPILE.rc) -I$(dir $<) $(PREPROCESS_FLAGS) $< $@

# For disassembly of object files
$(OUTPUT_OBJ_DIR)/%.disasm : $(OUTPUT_OBJ_DIR)/%.o
	@echo "OBJDUMP     : $(notdir $<)"
	@$(OBJDUMP) $(OBJDUMP_FLAGS) $< >$(OUTPUT_OBJ_DIR)/$*.disasm



ifeq ($(CROSS_COMPILING),1)

$(NATIVE_OUTPUT_OBJ_DIR)/%.o $(NATIVE_OUTPUT_OBJ_DIR)/%.d : %.mm
	@echo "NATIVE_CXX mm : $(notdir $<)"
	@$(NATIVE_CXX) $(NATIVE_PREPROCESS_FLAGS) $(DEPENDENCY_OPTIONS) '$(NATIVE_OUTPUT_OBJ_DIR)'/$*.o -MF $(NATIVE_OUTPUT_OBJ_DIR)/$*.d $< && $(NATIVE_COMPILE.mm) $(NATIVE_PREPROCESS_FLAGS) $(NATIVE_COMPILE_FLAGS) -o $(NATIVE_OUTPUT_OBJ_DIR)/$*.o $<

$(NATIVE_OUTPUT_OBJ_DIR)/%.o $(NATIVE_OUTPUT_OBJ_DIR)/%.d : %.m
	@echo "NATIVE_CC  m  : $(notdir $<)"
	@$(NATIVE_CC) $(NATIVE_PREPROCESS_FLAGS) $(DEPENDENCY_OPTIONS) -MT '$(NATIVE_OUTPUT_OBJ_DIR)'/$*.o -MF $(NATIVE_OUTPUT_OBJ_DIR)/$*.d $< && $(NATIVE_COMPILE.m) $(NATIVE_PREPROCESS_FLAGS) $(NATIVE_COMPILE_FLAGS) -o $(NATIVE_OUTPUT_OBJ_DIR)/$*.o $<

$(NATIVE_OUTPUT_OBJ_DIR)/%.o $(NATIVE_OUTPUT_OBJ_DIR)/%.d : %.cpp
	@echo "NATIVE_CXX    : $(notdir $<)"
	@$(NATIVE_CXX) $(NATIVE_PREPROCESS_FLAGS)  $(DEPENDENCY_OPTIONS) -MT '$(NATIVE_OUTPUT_OBJ_DIR)'/$*.o -MF $(NATIVE_OUTPUT_OBJ_DIR)/$*.d $< && $(NATIVE_COMPILE.cpp) $(NATIVE_PREPROCESS_FLAGS) $(NATIVE_COMPILE_FLAGS) -o $(NATIVE_OUTPUT_OBJ_DIR)/$*.o $<

$(NATIVE_OUTPUT_OBJ_DIR)/%.o $(NATIVE_OUTPUT_OBJ_DIR)/%.d : %.cc
	@echo "NATIVE_CXX    : $(notdir $<)"
	@$(NATIVE_CXX) $(NATIVE_PREPROCESS_FLAGS)  $(DEPENDENCY_OPTIONS) -MT  '$(NATIVE_OUTPUT_OBJ_DIR)'/$*.o -MF $(NATIVE_OUTPUT_OBJ_DIR)/$*.d $< && $(NATIVE_COMPILE.cpp) $(NATIVE_PREPROCESS_FLAGS) $(NATIVE_COMPILE_FLAGS) -o $(NATIVE_OUTPUT_OBJ_DIR)/$*.o $<

$(NATIVE_OUTPUT_OBJ_DIR)/%.o $(NATIVE_OUTPUT_OBJ_DIR)/%.d : %.c
	@echo "NATIVE_CC     : $(notdir $<)"
	@$(NATIVE_CC) $(NATIVE_PREPROCESS_FLAGS) $(DEPENDENCY_OPTIONS) -MT -MF  '$(NATIVE_OUTPUT_OBJ_DIR)'/$*.d $(NATIVE_OUTPUT_OBJ_DIR)/$*.d $< && $(NATIVE_COMPILE.c)  $(NATIVE_PREPROCESS_FLAGS) $(NATIVE_COMPILE_FLAGS) -o $(NATIVE_OUTPUT_OBJ_DIR)/$*.o $<

$(NATIVE_OUTPUT_OBJ_DIR)/%.o : %.rc
	@echo "NATIVE_WINDRES     : $(notdir $<)"
	@$(NATIVE_COMPILE.rc) -I$(dir $<) $(NATIVE_PREPROCESS_FLAGS) $< $@
endif


$(OUTPUT_TOOLS_DIR)/%$(EXE) : $(OUTPUT_OBJ_DIR)/%.o
	@echo "LINKING tool: $(notdir $<)"
	@$(LINK.cpp) $(LINK_FLAGS) $(LDFLAGS) -o $(OUTPUT_TOOLS_DIR)/$*$(EXE) $< -L$(OUTPUT_LIB_DIR) $(PROJECT_LDLIB) $(LDLIBS)


$(OUTPUT_GUI_DIR)/%$(EXE) : $(OUTPUT_OBJ_DIR)/%.o
	@echo "LINKING gui: $(notdir $<)"
	@$(LINK.cpp) $(LINK_FLAGS) $(LDFLAGS) $(LINK_FLAGS_GUI) -o $(OUTPUT_GUI_DIR)/$*$(EXE) $< -L$(OUTPUT_LIB_DIR) $(PROJECT_LDLIB) $(LDLIBS) $(LDLIBS_GUI)


$(OUTPUT_EXAMPLES_DIR)/%$(EXE) : $(OUTPUT_OBJ_DIR)/%.o
	@echo "LINKING example: $(notdir $<)"
	@$(LINK.cpp) $(LINK_FLAGS) $(LDFLAGS) -o $(OUTPUT_EXAMPLES_DIR)/$*$(EXE) $< -L$(OUTPUT_LIB_DIR) $(PROJECT_LDLIB) $(LDLIBS)

$(OUTPUT_TESTS_DIR)/%$(EXE) : $(OUTPUT_OBJ_DIR)/%.o
	@echo "LINKING test: $(notdir $<)"
	@$(LINK.cpp) $(LINK_FLAGS) $(LDFLAGS) -o $(OUTPUT_TESTS_DIR)/$*$(EXE) $< -L$(OUTPUT_LIB_DIR) $(PROJECT_LDLIB) $(LDLIBS)


ifeq ($(CROSS_COMPILING),1)

$(NATIVE_OUTPUT_TOOLS_DIR)/%$(NATIVE_EXE) : $(NATIVE_OUTPUT_OBJ_DIR)/%.o
	@echo "NATIVE_LINKING tool: $(notdir $<)"
	@$(NATIVE_LINK.cpp) $(NATIVE_LINK_FLAGS) $(NATIVE_LDFLAGS) -o $(NATIVE_OUTPUT_TOOLS_DIR)/$*$(NATIVE_EXE) $< -L$(NATIVE_OUTPUT_LIB_DIR) $(NATIVE_PROJECT_LDLIB) $(NATIVE_LDLIBS)

$(NATIVE_OUTPUT_EXAMPLES_DIR)/%$(NATIVE_EXE) : $(NATIVE_OUTPUT_OBJ_DIR)/%.o
	@echo "NATIVE_LINKING example: $(notdir $<)"
	@$(NATIVE_LINK.cpp) $(NATIVE_LINK_FLAGS) $(NATIVE_LDFLAGS) -o $(NATIVE_OUTPUT_EXAMPLES_DIR)/$*$(NATIVE_EXE) $< -L$(NATIVE_OUTPUT_LIB_DIR) $(NATIVE_PROJECT_LDLIB) $(NATIVE_LDLIBS)

$(NATIVE_OUTPUT_TESTS_DIR)/%$(NATIVE_EXE) : $(NATIVE_OUTPUT_OBJ_DIR)/%.o
	@echo "NATIVE_LINKING test: $(notdir $<)"
	@$(NATIVE_LINK.cpp) $(NATIVE_LINK_FLAGS) $(NATIVE_LDFLAGS) -o $(NATIVE_OUTPUT_TESTS_DIR)/$*$(NATIVE_EXE) $< -L$(NATIVE_OUTPUT_LIB_DIR) $(NATIVE_PROJECT_LDLIB) $(NATIVE_LDLIBS)
endif



# get the list of library source files from the src directory
LIB_CPP_FILES=$(call get_src_file_list,cpp)
LIB_CC_FILES=$(call get_src_file_list,cc)
LIB_C_FILES=$(call get_src_file_list,c)
LIB_M_FILES=$(call get_src_file_list,m)
LIB_MM_FILES=$(call get_src_file_list,mm)
LIB_RC_FILES=$(call get_src_file_list,rc)
LIB_O_FILES=$(call get_cpp_o_files,$(LIB_CPP_FILES)) \
	$(call get_cc_o_files,$(LIB_CC_FILES))  \
	$(call get_c_o_files,$(LIB_C_FILES)) \
	$(call get_m_o_files,$(LIB_M_FILES)) \
	$(call get_mm_o_files,$(LIB_MM_FILES)) \
	$(call get_rc_o_files,$(LIB_RC_FILES)) 

LIB_DISASM_FILES=$(LIB_O_FILES:.o=.disasm)


ifeq ($(CROSS_COMPILING),1)
NATIVE_LIB_CPP_FILES=$(call get_native_src_file_list,cpp)
NATIVE_LIB_CC_FILES=$(call get_native_src_file_list,cc)
NATIVE_LIB_C_FILES=$(call get_native_src_file_list,c)
NATIVE_LIB_M_FILES=$(call get_native_src_file_list,m)
NATIVE_LIB_MM_FILES=$(call get_native_src_file_list,mm)
NATIVE_LIB_RC_FILES=$(call get_native_src_file_list,rc)

NATIVE_LIB_O_FILES=$(call get_native_cpp_o_files,$(NATIVE_LIB_CPP_FILES)) \
	$(call get_native_cc_o_files,$(NATIVE_LIB_CC_FILES)) \
	$(call get_native_c_o_files,$(NATIVE_LIB_C_FILES)) \
	$(call get_native_m_o_files,$(NATIVE_LIB_M_FILES)) \
	$(call get_native_mm_o_files,$(NATIVE_LIB_MM_FILES)) \
	$(call get_native_rc_o_files,$(NATIVE_LIB_RC_FILES)) 
endif

LIB_INCLUDE_FILES=$(wildcard $(LIB_INCLUDE_DIR)/*.h) 


# get the list of tool program source files from the tools directories

$(eval $(call search_program_group,TOOLS))

# get the list of test program source files from the tests directories

$(eval $(call search_program_group,TESTS))

# get the list of example program source files from the examples directories

$(eval $(call search_program_group,EXAMPLES))

# get the list of example program source files from the gui directories

$(eval $(call search_program_group,GUI))


# if there are no O files to build, do not build or link a lib!

ifeq ($(strip $(LIB_O_FILES)),)
DO_NOT_BUILD_LIB=1
else
DO_NOT_BUILD_LIB=0
endif

ifeq ($(strip $(NATIVE_LIB_O_FILES)),)
NATIVE_DO_NOT_BUILD_LIB=1
else
NATIVE_DO_NOT_BUILD_LIB=0
endif


ifeq ($(DO_NOT_BUILD_LIB),1)
PROJECT_LDLIB=
else
PROJECT_LDLIB=-l$(PROJECT)
endif

ifeq ($(NATIVE_DO_NOT_BUILD_LIB),1)
NATIVE_PROJECT_LDLIB=
else
NATIVE_PROJECT_LDLIB=-l$(PROJECT)
endif

ifeq ($(DO_NOT_BUILD_LIB),1)
OUTPUT_LIB=
else
OUTPUT_LIB?=$(OUTPUT_LIB_DIR)/lib$(PROJECT).a
endif

ifeq ($(DO_NOT_BUILD_LIB),1)
NATIVE_OUTPUT_LIB=
else
NATIVE_OUTPUT_LIB?=$(NATIVE_OUTPUT_LIB_DIR)/lib$(PROJECT).a
endif






# manipulate these file lists to create our desired output files in the proper place

# this first target, 'everything' is a placeholder which makes the required subdirectories and then
# calls make again with the required directories made. Since these subdirectories are part of the
# search paths, make must see them when invoked otherwise it gets confused.

.PHONY : everything

ifeq ($(CROSS_COMPILING),1)
everything : native-dirs dirs
	@$(MAKE) all
else
everything : dirs
	@$(MAKE) all
endif


# load in any custom makefiles in every source directory
#-include $(wildcard $(foreach dir,$(ALL_SOURCES_DIRS),$(dir)/*.mak))


# win32_gui_program is a bit of a hack but it shows the future plan of allowing multi object programs being built.
# a program is defined my a dirname in gui/win32 - this dirname is the application name. Any sources in the dir are
# compiled and linked with the library

define win32_gui_program

vpath %.cpp $(PROJECT_TOP_DIR)/gui/win32/$(1)/
vpath %.cc $(PROJECT_TOP_DIR)/gui/win32/$(1)/
vpath %.c $(PROJECT_TOP_DIR)/gui/win32/$(1)/
vpath %.rc $(PROJECT_TOP_DIR)/gui/win32/$(1)/

LIB_GUI_EXE_FILES += $$(OUTPUT_GUI_DIR)/$(1)$$(EXE)

WIN32_GUI_DIR_$(1)=$$(PROJECT_TOP_DIR)/gui/win32/$(1)

#LIB_GUI_DIR += $$(WIN32_GUI_DIR_$(1))

WIN32_GUI_CPP_$(1)= $$(notdir $$(wildcard $$(PROJECT_TOP_DIR)/gui/win32/$(1)/*.cpp))
WIN32_GUI_CC_$(1)= $$(notdir $$(wildcard $$(PROJECT_TOP_DIR)/gui/win32/$(1)/*.cc))
WIN32_GUI_C_$(1)= $$(notdir $$(wildcard $$(PROJECT_TOP_DIR)/gui/win32/$(1)/*.c))
WIN32_GUI_RC_$(1)= $$(notdir $$(wildcard $$(PROJECT_TOP_DIR)/gui/win32/$(1)/*.rc))

WIN32_GUI_O_$(1)= $$(strip $$(WIN32_GUI_CPP_$(1):.cpp=.o) $$(WIN32_GUI_CC_$(1):.cc=.o) $$(WIN32_GUI_C_$(1):.c=.o) $$(WIN32_GUI_RC_$(1):.rc=.o))

gui :	$$(OUTPUT_GUI_DIR)/$(1)$$(EXE) 

$$(OUTPUT_GUI_DIR)/$(1)$$(EXE) : $$(addprefix $$(OUTPUT_OBJ_DIR)/, $$(WIN32_GUI_O_$(1)))
	@echo "LINKING MULTI-OBJECT GUI: $$(notdir $$@) from $$(notdir $$^)"
	@$$(LINK.cpp) $$(LINK_FLAGS) $$(LDFLAGS) $$(LINK_FLAGS_GUI) -o $$@ $$^ -L$$(OUTPUT_LIB_DIR) $$(PROJECT_LDLIB) $$(LDLIBS) $$(LDLIBS_GUI)

endef

ifneq ($(MAKE_VERSION),3.80)
ifeq ($(TARGET_PLATFORM_MINGW32),1)
$(foreach prog,$(call bare_subdirs_in_path,$(PROJECT_TOP_DIR)/gui/win32),$(eval $(call win32_gui_program,$(prog))))
endif
endif


.PHONY : all

ifeq ($(CROSS_COMPILING),1)
all : native-dirs dirs native-lib native-tools native-tests native-examples dirs lib tools tests examples gui
else
all : dirs lib tools tests examples gui
endif


.PHONY : dirs

dirs :
	-@$(MKDIR) -p $(ALL_OUTPUT_DIRS)


.PHONY : lib



ifeq ($(DO_NOT_BUILD_LIB),0)
lib : dirs $(OUTPUT_LIB)

$(OUTPUT_LIB) : $(LIB_O_FILES) 
ifeq ($(TARGET_USE_AR),1)
	@echo "AR     : $(notdir $@)($(notdir $?))"
	@$(AR) $(ARFLAGS) $@ $? >/dev/null
	@$(RANLIB) $@
endif
ifeq ($(TARGET_USE_MACOSX_LIBTOOL),1)
	@echo "LIBTOOL: $(notdir $@)($(notdir $?))"
#	@echo $(MACOSX_LIBTOOL) $(MACOSX_LIBTOOLFLAGS) -o $@ $^
	@$(MACOSX_LIBTOOL) $(MACOSX_LIBTOOLFLAGS) -o $@ $^
endif
else
lib : dirs
endif


.PHONY : tools

tools : lib $(LIB_TOOLS_EXE_FILES) config-tool

$(LIB_TOOLS_EXE_FILES) : $(OUTPUT_LIB)

.PHONY : examples

examples: lib $(LIB_EXAMPLES_EXE_FILES)

$(LIB_EXAMPLES_EXE_FILES) : $(OUTPUT_LIB)

.PHONY : tests

tests: lib $(LIB_TESTS_EXE_FILES)

$(LIB_TESTS_EXE_FILES) : $(OUTPUT_LIB)

.PHONY : gui

gui: lib $(LIB_GUI_EXE_FILES)

$(LIB_GUI_EXE_FILES) : $(OUTPUT_LIB)

.PHONY : install

install : all
	@-$(MKDIR) -p $(INSTALL_BIN_DIR)
	@for i in $(LIB_TOOLS_EXE_FILES) $(LIB_GUI_EXE_FILES); do echo "$${i}"; $(INSTALL) "$${i}" "$(INSTALL_BIN_DIR)"; done
	@$(CP) -rp $(OUTPUT_GUI_DIR) $(INSTALL_DIR) 


.PHONY : install-dev

install-dev : install
	@-$(MKDIR) -p $(INSTALL_INCLUDE_DIR) $(INSTALL_LIB_DIR)
	@for i in $(LIB_INCLUDE_DIR); do if [ -d "$${i}" ]; then $(RSYNC) $(RSYNC_OPTIONS) "$${i}"/* $(INSTALL_INCLUDE_DIR); fi; done
	@$(RSYNC) $(RSYNC_OPTIONS) $(OUTPUT_LIB) $(INSTALL_LIB_DIR) 
	@$(CP) -rp $(OUTPUT_TESTS_DIR) $(INSTALL_DIR)
	@$(CP) -rp $(OUTPUT_EXAMPLES_DIR) $(INSTALL_DIR) 
	@echo $(PROJECT_CONFIG_TOOL)
	@$(INSTALL) "$(CONFIG_TOOL_FILE)" "$(INSTALL_BIN_DIR)"

.PHONY : install-dev-docs

install-dev-docs : docs install-dev
	@-$(MKDIR) -p $(INSTALL_DOCS_DIR)
	@$(RSYNC) $(RSYNC_OPTIONS) $(OUTPUT_DOCS_DIR)/* $(INSTALL_DOCS_DIR)

.PHONY : test

ifeq ($(CROSS_COMPILING),1)
test : native-test
else
test: lib tools $(LIB_TESTS_SH_FILES) $(LIB_TESTS_EXE_FILES)
	@cd "$(OUTPUT_TESTS_DIR)"; \
	for i in $(LIB_TESTS_EXE_FILES); \
	do \
	  n=$$(basename $$i); \
	  if $(VALGRIND) $(VALGRIND_OPTIONS) "./$${n}" >"$${n}.out" 2>"$${n}.err"; then rm "$${n}.err"; echo SUCCESS:$${n}; else echo  FAIL:$${n}; fi;\
	done; \
	for i in $(LIB_TESTS_SH_FILES); \
	do \
	  n=$$(basename $$i); \
	  if bash "$${i}" >"$${n}.out" 2>"$${n}.err"; then rm "$${n}.err"; echo SUCCESS:$${n}; else echo  FAIL:$${n}; fi;\
	done
endif

.PHONY : docs

docs : lib $(LIB_DOCS_DIR)/Doxyfile
	@echo "DOCS :"
	@( export TOP="$(PROJECT_TOP_DIR)"; export PROJECT="$(PROJECT)"; export PROJECT_VERSION=$(PROJECT_VERSION); cd "$(OUTPUT_DOCS_DIR)" && $(DOXYGEN) $(LIB_DOCS_DIR)/Doxyfile )

.PHONY : clean

clean :
	-@$(RM) $(LIB_TESTS_O_FILES) $(LIB_EXAMPLES_O_FILES) $(LIB_TOOLS_O_FILES) $(LIB_O_FILES) $(OUTPUT_OBJ_DIR)/*.d 2>/dev/null
	-@$(RM) $(LIB_TESTS_EXE_FILES) $(LIB_EXAMPLES_EXE_FILES) $(LIB_TOOLS_EXE_FILES) 2>/dev/null
	-@$(RM) -r -f $(LIB_GUI_EXE_FILES) 2>/dev/null
ifeq ($(CROSS_COMPILING),1)
	-@$(RM) $(NATIVE_LIB_TESTS_O_FILES) $(NATIVE_LIB_EXAMPLES_O_FILES) $(NATIVE_LIB_TOOLS_O_FILES) $(NATIVE_LIB_O_FILES) $(NATIVE_OUTPUT_OBJ_DIR)/*.d 2>/dev/null
	-@$(RM) $(NATIVE_LIB_TESTS_EXE_FILES) $(NATIVE_LIB_EXAMPLES_EXE_FILES) $(NATIVE_LIB_TOOLS_EXE_FILES) 2>/dev/null
endif

.PHONY : realclean

realclean : distclean

.PHONY : distclean

distclean : clean
	-@$(RM) $(OUTPUT_LIB) 2>/dev/null
ifeq ($(CROSS_COMPILING),1)
	-@$(RM) $(NATIVE_OUTPUT_LIB) 2>/dev/null
endif


ifeq ($(CROSS_COMPILING),1)
.PHONY : native-dirs

native-dirs :
	-@$(MKDIR) -p $(NATIVE_ALL_OUTPUT_DIRS)

.PHONY : native-lib

ifeq ($(NATIVE_DO_NOT_BUILD_LIB),0)
native-lib : native-dirs $(NATIVE_OUTPUT_LIB)


$(NATIVE_OUTPUT_LIB) : $(NATIVE_LIB_O_FILES) 
ifeq ($(NATIVE_USE_AR),1)
	@echo "NATIVE_AR     : $(notdir $@)($(notdir $?))"
	@$(NATIVE_AR) $(NATIVE_ARFLAGS) $@ $? >/dev/null
	@$(NATIVE_RANLIB) $@
endif
ifeq ($(NATIVE_USE_MACOSX_LIBTOOL),1)
	@echo "NATIVE_LIBTOOL: $(notdir $@)($(notdir $?))"
#	@echo $(NATIVE_MACOSX_LIBTOOL) $(NATIVE_MACOSX_LIBTOOLFLAGS) -o $@ $^
	@$(NATIVE_MACOSX_LIBTOOL) $(NATIVE_MACOSX_LIBTOOLFLAGS) -o $@ $^
endif
endif

.PHONY : native-tools

native-tools : native-lib $(NATIVE_LIB_TOOLS_EXE_FILES)

$(NATIVE_LIB_TOOLS_EXE_FILES) : $(NATIVE_OUTPUT_LIB)

.PHONY : native-examples

native-examples: native-lib $(NATIVE_LIB_EXAMPLES_EXE_FILES)

$(NATIVE_LIB_EXAMPLES_EXE_FILES) : $(NATIVE_OUTPUT_LIB)

.PHONY : native-tests

native-tests: native-lib $(NATIVE_LIB_TESTS_EXE_FILES)

$(NATIVE_LIB_TESTS_EXE_FILES) : $(NATIVE_OUTPUT_LIB)

.PHONY : native-test

native-test: native-lib native-tools $(LIB_TESTS_SH_FILES) $(NATIVE_LIB_TESTS_EXE_FILES)
	@cd "$(NATIVE_OUTPUT_TESTS_DIR)"; \
	for i in $(NATIVE_LIB_TESTS_EXE_FILES); \
	do \
	  n=$$(basename $$i); \
	  if $(VALGRIND) $(VALGRIND_OPTIONS) "./$${n}" >"$${n}.out" 2>"$${n}.err"; then rm "$${n}.err"; echo SUCCESS:$${n}; else echo  FAIL:$${n}; fi;\
	done; \
	for i in $(LIB_TESTS_SH_FILES); \
	do \
	  n=$$(basename $$i); \
	  if bash "$${i}" >"$${n}.out" 2>"$${n}.err"; then rm "$${n}.err"; echo SUCCESS:$${n}; else echo  FAIL:$${n}; fi;\
	done

endif

.PHONY : disasm

disasm :  $(LIB_DISASM_FILES) $(LIB_EXAMPLES_DISASM_FILES) $(LIB_TOOLS_DISASM_FILES) $(LIB_TESTS_DISASM_FILES)


.PHONY : config-tool

config-tool : $(CONFIG_TOOL_FILE)

$(CONFIG_TOOL_FILE) :
	@-rm -f $(CONFIG_TOOL_FILE)
	@echo '#!/bin/bash' >$(CONFIG_TOOL_FILE)
	@echo 'for i in $$*; do' >>$(CONFIG_TOOL_FILE)
	@echo ' case $$i in ' >>$(CONFIG_TOOL_FILE)
	@echo '  (--ldflags) echo -n "$(LINK_FLAGS) $(LDFLAGS) -L$(INSTALL_LIB_DIR) ";;' >>$(CONFIG_TOOL_FILE)
	@echo '  (--ldlibs) echo -n "$(LDLIBS) $(PROJECT_LDLIB) ";;' >>$(CONFIG_TOOL_FILE)
	@echo '  (--cflags) echo -n "$(CFLAGS) $(CONFIG_TOOL_COMPILE_FLAGS) ";;' >>$(CONFIG_TOOL_FILE)
	@echo '  (--cxxflags) echo -n "$(CXXFLAGS) $(CONFIG_TOOL_COMPILE_FLAGS) ";;' >>$(CONFIG_TOOL_FILE)
	@echo '  (--cppflags) echo -n "$(addprefix -D,$(DEFINES)) ";;' >>$(CONFIG_TOOL_FILE)
	@echo '  (--mflags) echo -n "$(MFLAGS) $(CONFIG_TOOL_COMPILE_FLAGS) ";;' >>$(CONFIG_TOOL_FILE)
	@echo '  (--mmflags) echo -n "$(MMFLAGS) $(CONFIG_TOOL_COMPILE_FLAGS) ";;' >>$(CONFIG_TOOL_FILE)
	@echo ' esac' >>$(CONFIG_TOOL_FILE)
	@echo 'done' >>$(CONFIG_TOOL_FILE)
	@echo 'echo' >>$(CONFIG_TOOL_FILE)
	@chmod +x $(CONFIG_TOOL_FILE)

.PHONY : compile_info

compile_info :
	@echo "CC : $(CC)"
	@echo "CXX : $(CXX)"
	@echo "AR : $(AR)"
	@echo "RANLIB : $(RANLIB)"
	@echo "COMPILE_FLAGS: $(COMPILE_FLAGS)"
	@echo "LINK_FLAGS: $(LINK_FLAGS)"
	@echo "LDLIBS: $(LDLIBS)"
	@echo "OUTPUT_LIB: $(OUTPUT_LIB)"	
	@echo "LIB_DIRS: $(LIB_DIRS)"
	@echo "PLATFORM_DIRS: $(PLATFORM_DIRS)"
	@echo "LIB_INCLUDE_DIR: $(LIB_INCLUDE_DIR)"
	@echo "LIB_SRC_DIR: $(LIB_SRC_DIR)"
	@echo "LIB_TESTS_DIR: $(LIB_TESTS_DIR)"
	@echo "LIB_TOOLS_DIR: $(LIB_TOOLS_DIR)"
	@echo "LIB_EXAMPLES_DIR: $(LIB_EXAMPLES_DIR)"
	@echo "LIB_GUI_DIR: $(LIB_GUI_DIR)"
	@echo "LIB_CPP_FILES: $(LIB_CPP_FILES)"
	@echo "LIB_CC_FILES: $(LIB_CC_FILES)"
	@echo "LIB_C_FILES: $(LIB_C_FILES)"
	@echo "LIB_MM_FILES: $(LIB_MM_FILES)"
	@echo "LIB_M_FILES: $(LIB_M_FILES)"
	@echo "LIB_RC_FILES: $(LIB_RC_FILES)"
	@echo "LIB_O_FILES: $(notdir $(LIB_O_FILES))"
	@echo "LIB_TOOLS_EXE_FILES: $(notdir $(LIB_TOOLS_EXE_FILES))"
	@echo "LIB_EXAMPLES_EXE_FILES: $(notdir $(LIB_EXAMPLES_EXE_FILES))"
	@echo "LIB_TESTS_EXE_FILES: $(notdir $(LIB_TESTS_EXE_FILES))"
	@echo "LIB_GUI_EXE_FILES: $(notdir $(LIB_GUI_EXE_FILES))"
	@echo "BUILD_DIR: $(OUTPUT_DIR)"
	@echo "OUTPUT_DIR: $(OUTPUT_DIR)"
	@echo "OUTPUT_LIB_DIR: $(OUTPUT_LIB_DIR)"
	@echo "OUTPUT_TESTS_DIR: $(OUTPUT_TESTS_DIR)"
	@echo "OUTPUT_DOCS_DIR: $(OUTPUT_DOCS_DIR)"
	@echo "OUTPUT_TOOLS_DIR: $(OUTPUT_TOOLS_DIR)"
	@echo "OUTPUT_GUI_DIR: $(OUTPUT_GUI_DIR)"
	@echo "OUTPUT_EXAMPLES_DIR: $(OUTPUT_EXAMPLES_DIR)"
	@echo "OUTPUT_OBJ_DIR: $(OUTPUT_OBJ_DIR)"
	@echo "INSTALL_DIR: $(INSTALL_DIR)"
ifeq ($(CROSS_COMPILING),1)
	@echo "NATIVE_CC : $(NATIVE_CC)"
	@echo "NATIVE_CXX : $(NATIVE_CXX)"
	@echo "NATIVE_AR : $(NATIVE_AR)"
	@echo "NATIVE_RANLIB : $(NATIVE_RANLIB)"
	@echo "NATIVE_COMPILE_FLAGS: $(NATIVE_COMPILE_FLAGS)"
	@echo "NATIVE_LINK_FLAGS: $(NATIVE_LINK_FLAGS)"
	@echo "NATIVE_LDLIBS: $(NATIVE_LDLIBS)"
	@echo "NATIVE_OUTPUT_LIB: $(NATIVE_OUTPUT_LIB)"
	@echo "NATIVE_LIB_SRC_DIR: $(NATIVE_LIB_SRC_DIR)"
	@echo "NATIVE_LIB_TOOLS_DIR: $(NATIVE_LIB_TOOLS_DIR)"
	@echo "NATIVE_PLATFORM_DIRS: $(NATIVE_PLATFORM_DIRS)"
endif

.PHONY : help

help :
	@echo "TOP of source is $(PROJECT_TOP_DIR)"
	@echo "compile_info : show compile flags, directories, options"
	@echo "lib : build library $(OUTPUT_LIB)"
	@echo "docs : build doxygen docs in $(PROJECT_TOP_DIR)/docs/html"
	@echo "clean : clean intermediate files"
	@echo "distclean / realclean : clean all built files (except docs)"
	@echo "tools : build tool programs $(LIB_TOOLS_EXE_FILES)"
	@echo "examples : build example programs $(LIB_EXAMPLES_EXE_FILES)"
	@echo "tests : build test programs $(LIB_TESTS_EXE_FILES)"
	@echo "test : run tests, sh scripts and test programs"
	@echo "dirs : create output dirs $(OUTPUT_DIR)"
	@echo "install : install tool executables files into $(INSTALL_DIR)"
	@echo "install-dev : install tool executables, include files and library files into $(INSTALL_DIR)"
	@echo "install-dev-docs : install tool executables, include files, library files, and doxygen docs into $(INSTALL_DIR)"
ifeq ($(CROSS_COMPILING),1)
	@echo "native-dirs : create output dirs for native build in $(NATIVE_OUTPUT_DIR)"
	@echo "native-lib : build native library $(NATIVE_OUTPUT_LIB)"
	@echo "native-tests : build native tests $(NATIVE_LIB_TESTS_EXE_FILES)"
	@echo "native-test : run native tests."
endif

# read any custom mak files in the top dir of each library dir / project

-include $(foreach dir,$(LIB_DIRS),$(dir)/$(dir).mak)

# include any dependencies created during the last make.
-include $(OUTPUT_OBJ_DIR)/*.d

ifeq ($(CROSS_COMPILING),1)
-include $(NATIVE_OUTPUT_OBJ_DIR)/*.d
endif






